import stackless
import math

def dot_product(v1, v2):
    return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z

def cross_product(v1, v2):
    return Vector(v1.y*v2.z - v1.z*v2.y,
                  v1.z*v2.x - v1.x*v2.z,
                  v1.x*v2.y - v1.y*v2.x)

class Quaternion(object):
    def __init__(self, w, x, y, z):
        self.w = w
        self.v = Vector(x, y, z)

    def __mul__(self, q):
        return Quaternion(self.w*q.w - dot_product(self.v, q.v),
                        *(self.w*q.v + q.w*self.v + cross_product(self.v, q.v)))
    
    def __imul__(self, q):
        return Quaternion(self.w*q.w - dot_product(self.v, q.v),
                        *(q.v*self.w + self.v*q.w + cross_product(self.v, q.v)))

class Vector(object):
    def __init__(self, x, y, z):
        self.x = x
        self.y = y
        self.z = z
        self._index = {0: self.x, 1: self.y, 2: self.z}
    
    def __getitem__(self, index):
        try:
            return self._index[index]
        except KeyError:
            raise StopIteration
    
    def __add__(self, amount):
        return Vector(self.x + amount.x,
                      self.y + amount.y,
                      self.z + amount.z)

    def __iadd__(self, amount):
        self.x = self.x + amount.x
        self.y = self.y + amount.y
        self.z = self.z + amount.z
        return self
    
    def __mul__(self, amount):
        return Vector(self.x * amount,
                      self.y * amount,
                      self.z * amount)

    def __imul__(self, amount):
        self.x = self.x * amount
        self.y = self.y * amount
        self.z = self.z * amount
        return self
    
    def __repr__(self):
        return "Vector(%f, %f, %f)" % (self.x, self.y, self.z)

    def __isub__(self, amount):
        self.x = self.x - amount.x
        self.y = self.y - amount.y
        self.z = self.z - amount.z
        return self
    
    def copy(self):
        return Vector(self.x, self.y, self.z)

    def magnitude_squared(self):
        return self.x**2 + self.y**2 + self.z**2

    def magnitude(self):
        return math.sqrt(self.magnitude_squared())

    def normalise(self):
        mag = self.magnitude()
        self.x = self.x / mag
        self.y = self.y / mag
        self.z = self.z / mag

class Actor(object):
    def __init__(self):
        self.channel = stackless.channel()
        stackless.tasklet(self.receive_messages)()

    def receive_messages(self):
        print "receiving"
        while True:
            self.process_message(*self.channel.receive())

    def process_message(self, action, args):
        print "Use your own method", action, args
